package com.webuploader.demo.clicnt;

import org.apache.commons.io.FileUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.HttpClients;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.*;
import java.net.URLEncoder;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @Author xiang
 * @Date 2021/5/18 13:07
 * @Version 1.0
 * 文件下载客服端
 */
@RestController
public class DownLoadClicnt {
    private final static long PER_PAGE=1024L * 1024L *50L;
    private final  static String DOWN_PATH="F:\\fileItem";
    private final  static  String utf8="utf-8";
    ExecutorService pool= Executors.newFixedThreadPool(10);

    //文件大小  文件名字
    //探测 获取文件信息
    //使用多线程分片下载
    //最后一个分片下载玩 开始合并
    @RequestMapping("/")
    public String  downloadFile() throws IOException, InterruptedException {
        FileInfo fileInfo=download(0,10,-1,null);
        if(fileInfo !=null){
            long pages=fileInfo.fSize/PER_PAGE;
            for (long i=0;i<pages;i++){
                pool.submit(new DownLoad(i*PER_PAGE,(i+1)*PER_PAGE-1,i,fileInfo.fName));
            }
        }
        return  "success";
    }
    class  DownLoad implements  Runnable{
        long start,end,page;
        String fName;

        public DownLoad(long start, long end, long page, String fName) {
            this.start = start;
            this.end = end;
            this.page = page;
            this.fName = fName;
        }

        @Override
        public void run() {
            try {
                download(start,end,page,fName);
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }

    class FileInfo{
        long fSize;
        String fName;

        public FileInfo(long fSize, String fName) {
            this.fSize = fSize;
            this.fName = fName;
        }
    }

    //结束位置-开始位置 =分片大小
    //零时存储分片文件
    private FileInfo download(long start, long end,long page,String fName) throws IOException, InterruptedException {
        //断点下载
        File file= new File(DOWN_PATH,page+"-"+fName);
        if(file.exists() && page != -1&& file.length()==PER_PAGE){
            return  null;
        }
        HttpClient client= HttpClients.createDefault();
        HttpGet httpGet= new HttpGet("http://127.0.0.1:8080/download");
        httpGet.setHeader("Range","bytes="+start+"-"+end);
        HttpResponse response=client.execute(httpGet);
        String fSize=response.getFirstHeader("fSize").getValue();
        fName= URLEncoder.encode(response.getFirstHeader("fName").getValue(),utf8);

        HttpEntity entity=response.getEntity();
        //拿到文件内容
        InputStream is= entity.getContent();

        FileOutputStream fos= new FileOutputStream(file);

        byte [] buffer =new byte[1024];
        int ch;
        while ((ch=is.read(buffer))!=-1){
            fos.write(buffer,0,ch);
        }
        is.close();
        fos.flush();
        fos.close();
        //判断是否为最后一个分片
        if(end -Long.valueOf(fSize)>0){
            mergeFile(fName,page);
        }
        return new FileInfo(Long.valueOf(fSize),fName);
    }

    private void mergeFile(String fName, long page) throws IOException, InterruptedException {
        File file= new File(DOWN_PATH,fName);
        BufferedOutputStream os=new BufferedOutputStream(new FileOutputStream(file));

        for(int i=0;i<=page;i++){
            File temFile=new File(DOWN_PATH,i+"-"+fName);
            while (file.exists() || (i!=page && temFile.length()<PER_PAGE)){
                Thread.sleep(100);
            }
            byte [] bytes=FileUtils.readFileToByteArray(temFile);
            os.write(bytes);
            os.flush();
            //删除零时文件
            temFile.delete();
        }
        //删除探测文件
        File file1=new File(DOWN_PATH,-1+"-null");
        file1.delete();
        os.flush();
        os.close();
    }
}
